package com.neusoft.databus.policy.event.impl;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.eventbus.AsyncEventBus;
import com.neusoft.bizcore.common.cache.CacheService;
import com.neusoft.bizcore.web.utils.JsonUtils;
import com.neusoft.databus.common.bean.MetricBean;
import com.neusoft.databus.common.bean.ResourceBean;
import com.neusoft.databus.policy.constants.DatabusPolicyConstant;
import com.neusoft.databus.policy.enums.EventStatus;
import com.neusoft.databus.policy.enums.PolicyType;
import com.neusoft.databus.policy.event.PolicyEventHandler;
import com.neusoft.databus.policy.model.Event;
import com.neusoft.databus.policy.model.EventAttribute;
import com.neusoft.databus.policy.model.Policy;
import com.neusoft.databus.policy.utils.PolicyUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 策略告警事件处理类
 *
 * @author naxiang
 */
@Slf4j
@Component("policyEventHandler")
public class PolicyEventHandlerImpl extends PolicyEventHandler {
    @Autowired
    protected CacheService cacheService;

    @Autowired
    protected AsyncEventBus policyEventBus;

    @Override
    public void trigger(ResourceBean resourceBean, Date time, Policy policy,
            final List<Integer> expressionTrueSquence) {
        final String resourceCode = resourceBean.getCode();
        final String key = PolicyUtil.getEventKey(resourceCode, policy.getCode());
        Event event = null;
        try {
            event = this.getEvent(policy, resourceCode);
            final StringBuffer metricCode = new StringBuffer();
            policy.getExpressions().forEach(e -> {
                if (StringUtils.isNoneBlank(e.getExpressionInfo())) {
                    final Map<String, Object> expression = JsonUtils.jsonToMap(e.getExpressionInfo());
                    metricCode.append(expression.get(DatabusPolicyConstant.METRICCODE));
                    metricCode.append(",");
                }
            });
            event.setMetricCode(metricCode.substring(0, metricCode.lastIndexOf(",")));
            final EventAttribute eventAttibute = event.getEventAttribute();
            eventAttibute.setLastTime(time);
            // 普通策略
            if (PolicyType.POLICY_ALARM.equals(policy.getPolicyType())) {
                eventAttibute.setContent(this.buildAlertContent(expressionTrueSquence, policy.getContentTemplate(),
                        resourceBean.getMetrics(), event));
                // 复杂策略
            } else if (PolicyType.POLICY_COMPLEX.equals(policy.getPolicyType())) {
                eventAttibute.setContent(this.buildAlertContent(policy.getContentTemplate()));
            }
            event.setStatus(EventStatus.UNFIXED);
            synchronized (this.getLockInstance(resourceCode)) {
                if (!this.cacheService.isInCache(PolicyEventHandler.cacheName,
                        key)) {
                    this.cacheService.put(PolicyEventHandler.cacheName,
                            key, event.getCode());
                } else {
                    event.setCode(String.valueOf(this.cacheService.get(
                            PolicyEventHandler.cacheName, key)));
                }
            }
            this.policyEventBus.post(event);
        } catch (final Exception e) {
            PolicyEventHandlerImpl.log.error("告警事件,策略code:{},资源code:{},产生异常{}", policy.getCode(), resourceCode, e);
        } finally {
            // 置空大对象,以免内存增长过快
            time = null;
            event = null;
            resourceBean = null;
            policy = null;
        }
    }

    @Override
    public void fixed(ResourceBean resourceBean, Date time, Policy policy) {
        final String resourceCode = resourceBean.getCode();
        final String key = PolicyUtil.getEventKey(resourceCode, policy.getCode());
        Event event = this.getEvent(policy, resourceCode);
        event.setStatus(EventStatus.FIXED);
        try {
            synchronized (this.getLockInstance(resourceCode)) {
                if (!this.cacheService.isInCache(PolicyEventHandler.cacheName, key)) {
                    PolicyEventHandlerImpl.log.debug("缓存中未查询到设备的告警事件{}", key);
                    return;
                }
                final String code = (String) this.cacheService.get(PolicyEventHandler.cacheName, key);
                event.setCode(code);
                event.setFixTime(time);
                this.policyEventBus.post(event);
            }
        } catch (final Exception e) {
            PolicyEventHandlerImpl.log.error("告警解除事件,策略code:{},资源code:{},产生异常{}", policy.getCode(), resourceCode, e);
        } finally {
            // 置空大对象,以免内存增长过快
            time = null;
            event = null;
            resourceBean = null;
            policy = null;
        }
    }

    /**
     * 告警提示信息
     *
     * @param expressionTrueSquence
     * @param eventContent
     * @param metrics
     * @param event
     * @return
     */
    private String buildAlertContent(List<Integer> expressionTrueSquence, String eventContent,
            List<MetricBean> metrics, final Event event) {
        Map<String, Object> contentJson = JsonUtils.jsonToMap(eventContent);
        if (contentJson == null) {
            return "";
        }
        if (contentJson.containsKey("-1")) {
            return String.valueOf(contentJson.get("-1"));
        }
        final StringBuffer contentSb = new StringBuffer();
        final Pattern p = Pattern.compile("#.*?#");
        for (final Integer squence : expressionTrueSquence) {
            if (!contentJson.containsKey(String.valueOf(squence))) {
                continue;
            }
            String content = contentJson.get(String.valueOf(squence)).toString();
            final Matcher m = p.matcher(content);
            if (!content.matches(".*#.*?#.*")) {
                contentSb.append(content).append(";");
                continue;
            }
            while (m.find()) {
                final String metricCode = m.group().replaceAll("#", "");// 去掉#
                for (final MetricBean metric : metrics) {
                    if (metricCode.endsWith(metric.getCode())) {
                        content = content
                                .replaceAll("#" + metricCode + "#", String.valueOf(metric.getValue().toString()))
                                .replace(metric.getCode(), metric.getName());
                        break;
                    }
                }
                contentSb.append(content);
                contentSb.append(";");
            }
        }
        contentJson = null;
        expressionTrueSquence = null;
        eventContent = null;
        metrics = null;
        return contentSb.toString();
    }

    /**
     * 告警提示信息
     *
     * @param originalContent
     * @return
     */
    private String buildAlertContent(final String originalContent) {
        final Map<String, Object> contentMap = JsonUtils.jsonToMap(originalContent);
        if (contentMap == null) {
            return "";
        }
        final String key = "-1";
        if (contentMap.containsKey(key)) {
            return contentMap.get(key).toString();
        }
        return "";
    }
}
